package com.kgcx.organization.service;

import com.github.pagehelper.PageHelper;
import com.kgcx.common.bean.RequestData;
import com.kgcx.common.constant.Cons;
import com.kgcx.common.mqtt.TopicConst;
import com.kgcx.common.redis.JsonRedisTemplate;
import com.kgcx.common.utils.AuroraPush;
import com.kgcx.common.utils.TokenUtils;
import com.kgcx.core.utils.HelpUtil;
import com.kgcx.core.utils.JsonUtil;
import com.kgcx.dbutils.utils.PageUtils;
import com.kgcx.organization.domain.*;
import com.kgcx.organization.mapper.*;
import com.kgcx.organization.rabbitmq.producer.AutoOperateProducer;
import com.kgcx.organization.rabbitmq.producer.DriverProducer;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class DriverService {
    private static final Logger LOG = LoggerFactory.getLogger(DriverService.class);
    private static final String INVITE_PARK_TYPE_JPUSH = "jpush"; // 极光APP消息推送
    private static final String INVITE_PARK_TYPE_MQTT = "mqtt"; // MQTT长连接

    @Value("${kgcx.driver.invite-park-type:jpush}")
    private String inviteParkType;
    @Value("${kgcx.driver.notify-state-type:jpush}")
    private String notifyStateType;

    @Autowired(required = false)
    private MqttClient mqttProducer;

    @Autowired
    private DriverMapper driverMapper;

    @Autowired
    private AutoService autoService;

    @Autowired
    private DriverStateRecordMapper driverStateRecordMapper;
    @Autowired
    private AirportParkingMapper airportParkingMapper;
    @Autowired
    private StationParkingMapper stationParkingMapper;
    @Autowired
    private DriverParkingMapper driverParkingMapper;
    @Autowired
    private DriverStayMapper driverStayMapper;
    @Autowired
    private DriverMobileTerminalService driverMobileTerminalService;
    @Autowired
    private DriverProducer driverProducer;

    @Autowired
    private AutoOperateProducer autoOperateProducer;

    @Autowired
    private JsonRedisTemplate jsonRedisTemplate;

    public static String getMD5Password(String phone, String password) {
        return DigestUtils.md5Hex(phone + password);
    }

    public Driver getDriver(RequestData rd) {
        if (StringUtils.isNotBlank(rd.getString("token"))) {
            rd.put("kid", TokenUtils.getId(rd.getString("token")));
        }
        Driver driver = driverMapper.getDriver(rd);
        return driver;
    }

    public Driver getDriver(Long kid, String phone) {
        RequestData rd = new RequestData();
        rd.put("kid", kid);
        rd.put("phone", phone);
        return driverMapper.getDriver(rd);
    }

    public List<Driver> getDriverList(RequestData rd) {
        PageUtils.page(rd);
        PageHelper.orderBy(rd.getOrderBy());
        List<Driver> list = driverMapper.selectDriverList(rd);
        return list;
    }

    /**
     * 司机信息放到MQ里面给监管平台
     *
     * @param rd
     * @return
     */
    public List<Driver> queryDriverWithPage(RequestData rd) {
        PageUtils.page(rd);
        PageHelper.orderBy(rd.getOrderBy());
        List<Driver> list = driverMapper.selectDriverList(rd);
        for (Driver driver : list) {
            driverProducer.addDriver(driver);
        }
        return list;
    }

    public Driver login(RequestData rd) {
        Driver driverSelect = new Driver();
        String phone = rd.getString("phone");
        String password = rd.getString("password");
        driverSelect.setPhone(phone);
        driverSelect.setPassword(getMD5Password(phone, password));
        Driver driver = driverMapper.selectOneActive(driverSelect);
        return driver;
    }

    @Transactional(rollbackFor = Exception.class)
    public void addDriver(Driver driver) {
        String password = driver.getPassword();
        if (StringUtils.isEmpty(password)) {
            password = Driver.DEFAULT_PASSWORD;
        }
        driver.setPassword(getMD5Password(driver.getPhone(), password));
        driverMapper.insertSelective(driver);


        driverMobileTerminalService.insertByDriver(driver);
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateDriver(Driver driver) {
        if (StringUtils.isNotEmpty(driver.getPassword())) {
            driver.setPassword(getMD5Password(driver.getPhone(), driver.getPassword()));
        }
        driverMapper.updateByPrimaryKeySelective(driver);

        driverProducer.updateDriver(driver);

        driverMobileTerminalService.updateByDriver(driver);
    }

    @Transactional(rollbackFor = Exception.class)
    public void resetPassword(String phone, String password) {
        Driver driver = getDriver(null, phone);
        driver.setPassword(getMD5Password(phone, password));
        driverMapper.updateByPrimaryKeySelective(driver);
    }

    @Transactional(rollbackFor = Exception.class)
    public void removeDriver(Long kid) {
        Driver driver = new Driver();
        driver.setKid(kid);
        driver.setStatus(Cons.COMMON_STATUS_DELETE);
        driverMapper.updateByPrimaryKeySelective(driver);

        driverProducer.deleteDriver(driver);
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateDriverState(Long kid, Integer state, String lat, String lng) {
        updateDriverState(kid, state, lat, lng, null, null);
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateDriverState(Long kid, Integer state, String lat, String lng, Long airportId, Long stationId) {
        Driver driver = addDriverStateRecord(kid, state, lat, lng, airportId, stationId);

        if (Cons.DRIVER_STATE_ON.equals(state) || Cons.DRIVER_STATE_OFF.equals(state)) {
            driver = getDriver(kid, null);
            driver.setLat(lat);
            driver.setLng(lng);
            if (Cons.DRIVER_STATE_ON.equals(state)) {
                autoOperateProducer.login(driver);
            } else if (Cons.DRIVER_STATE_OFF.equals(state)) {
                autoOperateProducer.logout(driver);
            }
        }

        processParking(kid, state, airportId, stationId);
    }

    private Driver addDriverStateRecord(Long kid, Integer state, String lat, String lng, Long airportId,
                                        Long stationId) {
        return addDriverStateRecord(kid, state, lat, lng, airportId, stationId,
                new Timestamp(System.currentTimeMillis()));
    }

    private Driver addDriverStateRecord(Long kid, Integer state, String lat, String lng, Long airportId, Long stationId,
                                        Timestamp lastUpdateStateTime) {
        Driver driver = new Driver();
        driver.setKid(kid);
        driver.setState(state);
        driver.setLastUpdateStateTime(lastUpdateStateTime);
        if (Cons.DRIVER_STATE_ON.equals(state) || Cons.DRIVER_STATE_OFF.equals(state)) {
            driver.setAirportId(-1L);
            driver.setStationId(-1L);
        } else if (Cons.DRIVER_STATE_STAY.equals(state)) {
            if (airportId != null) {
                driver.setAirportId(airportId);
                driver.setStationId(-1L);
            } else if (stationId != null) {
                driver.setAirportId(-1L);
                driver.setStationId(stationId);
            }
        }
        driverMapper.updateByPrimaryKeySelective(driver);

        DriverStateRecord driverStateRecord = new DriverStateRecord();
        driverStateRecord.setDriverId(kid);
        driverStateRecord.setState(state);
        driverStateRecord.setLat(lat);
        driverStateRecord.setLng(lng);
        driverStateRecord.setCreateTime(lastUpdateStateTime);
        // driverStateRecord.setUpdateTime(updateTime);
        driverStateRecordMapper.insertSelective(driverStateRecord);

        return driver;
    }

    private void processParking(Long driverId, Integer driverState, Long airportId, Long stationId) {
        if (Cons.DRIVER_STATE_OFF.equals(driverState) || Cons.DRIVER_STATE_ON.equals(driverState)) { // 司机状态变为下线或者上线
            // 从待安排车位（待命）列表中移除
            removeDriverStay(driverId);
            // 移入历史表、解锁车位、给下一个司机发送入栈邀请
            archiveDriverParking(driverId);
        } else if (Cons.DRIVER_STATE_STAY.equals(driverState)) { // 司机状态变为待命
            // 如果司机端进程被杀掉，没有答复待命邀请，这里要重新发送一次邀请
            AbstractParking parking = airportParkingMapper.getParkingByDriverId(driverId);
            if (parking == null) {
                parking = stationParkingMapper.getParkingByDriverId(driverId);
            }
            if (parking != null) {
                notifyDriverParking(driverId, parking); // 通知司机端APP弹出入栈邀请对话框，重新操作一遍入栈确认流程
                return;
            }

            // 给最早待命的司机发送入栈邀请
            if (airportId != null) {
                addDriverStay(driverId, airportId, stationId);
                sendAirportInInvitationToDriver(airportId);
            } else if (stationId != null) {
                addDriverStay(driverId, airportId, stationId);
                sendStationInInvitationToDriver(stationId);
            }
        } else if (Cons.DRIVER_STATE_PREIN.equals(driverState) || Cons.DRIVER_STATE_IN.equals(driverState)) { // 司机状态变为入栈中或者入栈
            // 理论上，前端是不应该发送修改为该状态的请求给后台，所以我们这里不做任何处理
        } else if (Cons.DRIVER_STATE_RUN.equals(driverState)) { // 司机状态变为服务中
            // 服务中时（接单），不需要解锁车位，同时也不需要调派车位给司机
            removeDriverStay(driverId);
        } else {
        }
    }

    /**
     * 移入历史表、解锁车位、给下一个司机发送入栈邀请
     *
     * @param driverId
     */
    private void archiveDriverParking(Long driverId) {
        AirportParking airportParking = airportParkingMapper.getParkingByDriverId(driverId);
        if (airportParking != null) {
            archiveDriverParking(airportParking, AbstractParking.STATUS_CANCELLED);
            return;
        }

        StationParking stationParking = stationParkingMapper.getParkingByDriverId(driverId);
        if (stationParking != null) {
            archiveDriverParking(stationParking, AbstractParking.STATUS_CANCELLED);
            return;
        }
    }

    private void addDriverStay(Long driverId, Long airportId, Long stationId) {
        Map<String, Object> rowMap = new HashMap<String, Object>();
        rowMap.put("driver_id", driverId);
        rowMap.put("airport_id", airportId);
        rowMap.put("station_id", stationId);
        rowMap.put("stay_time", HelpUtil.getNowTime());
        driverStayMapper.insert(rowMap);
    }

    private void removeDriverStay(Long driverId) {
        // 从待安排车位（待命）列表中移除
        driverStayMapper.deleteByDriverId(driverId);
    }

    private void sendAirportInInvitationToDriver(Long airportId) {
        AirportParking airportParking = new AirportParking();
        airportParking.setStatus(Cons.COMMON_STATUS_ACTIVE);
        airportParking.setAirportId(airportId);
        List<AirportParking> list = airportParkingMapper.getUnusedParking(airportParking);
        if (HelpUtil.isEmpty(list)) {
            return;
        }

        for (AirportParking parking : list) {
            Long driverId = driverStayMapper.selectDriverIdByAirportId(airportId);
            if (driverId == null) {
                return;
            }

            parking.setDriverId(driverId);
            parking.setInviteTime(HelpUtil.getNowTime());
            parking.setParkBeginTime(null);
            parking.setParkState(AbstractParking.STATE_UNCONFIRM);
            airportParkingMapper.updateParkState(parking);

            driverStayMapper.deleteByDriverId(driverId);

            notifyDriverParking(driverId, parking);
        }
    }

    private void sendStationInInvitationToDriver(Long stationId) {
        StationParking stationParking = new StationParking();
        stationParking.setStatus(Cons.COMMON_STATUS_ACTIVE);
        stationParking.setStationId(stationId);
        List<StationParking> list = stationParkingMapper.getUnusedParking(stationParking);
        if (HelpUtil.isEmpty(list)) {
            return;
        }

        for (StationParking parking : list) {
            Long driverId = driverStayMapper.selectDriverIdByStationId(stationId);
            if (driverId == null) {
                return;
            }

            parking.setDriverId(driverId);
            parking.setInviteTime(HelpUtil.getNowTime());
            parking.setParkBeginTime(null);
            parking.setParkState(AbstractParking.STATE_UNCONFIRM);
            stationParkingMapper.updateParkState(parking);

            driverStayMapper.deleteByDriverId(driverId);

            notifyDriverParking(driverId, parking);
        }
    }

    private void notifyDriverParking(Long driverId, AbstractParking parking) {
        try {
            if (INVITE_PARK_TYPE_MQTT.equals(inviteParkType)) {
                notifyDriverParkingByMqtt(driverId, parking);
            } else {
                notifyDriverParkingByMqttJpush(driverId, parking);
            }
            LOG.info(String.format("给司机[%d]推送入栈邀请成功，推送方式为%s。", driverId, inviteParkType));
        } catch (Exception e) {
            LOG.error(String.format("给司机[%d]推送入栈邀请失败，推送方式为%s。", driverId, inviteParkType), e);
        }
    }

    private void notifyDriverParkingByMqtt(Long driverId, AbstractParking parking) throws MqttException {
        if (mqttProducer == null) {
            LOG.warn(String.format("司机[%d]，MQTT功能未开启，转为jpush推送。请确认kgcx.mqtt.enable配置属性的值是否为true。", driverId));
            notifyDriverParkingByMqttJpush(driverId, parking);
            return;
        }

        MqttMessage message = new MqttMessage();
        message.setQos(1);
        message.setRetained(false); // 是否是实时发送的消息
        message.setPayload(JsonUtil.toString(parking).getBytes());

        MqttTopic topic = mqttProducer.getTopic(TopicConst.DRIVER_INVITE_PARK + "." + driverId);
        topic.publish(message);
    }

    private void notifyDriverParkingByMqttJpush(Long driverId, AbstractParking parking) {
        // 发送消息
        AuroraPush.pushTargetMsgForDriver(TopicConst.DRIVER_INVITE_PARK, JsonUtil.toString(parking),
                String.valueOf(driverId), AuroraPush.PLATFORM_ANDROID);
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateParkState(Long driverId, Integer parkState) {
        Driver driver = driverMapper.selectByPrimaryKey(driverId);
        AirportParking airportParking = airportParkingMapper.getParkingByDriverId(driverId);
        if (airportParking != null) {
            updateAirportParkState(driver, airportParking, parkState);
            return;
        }

        StationParking stationParking = stationParkingMapper.getParkingByDriverId(driverId);
        if (stationParking != null) {
            updateStationParkState(driver, stationParking, parkState);
            return;
        }
    }

    private void updateAirportParkState(Driver driver, AirportParking parking, Integer parkState) {
        if (AbstractParking.STATUS_PREIN.equals(parkState)) {
            parking.setParkState(parkState);
            parking.setParkBeginTime(HelpUtil.getNowTime());
            airportParkingMapper.updateParkState(parking);

            if (!Cons.DRIVER_STATE_RUN.equals(driver.getState())) { // 没有接单时，才同步修改司机状态为入栈中。
                addDriverStateRecord(parking.getDriverId(), Cons.DRIVER_STATE_PREIN, null, null, null, null);
            }
            return;
        }

        if (AbstractParking.STATUS_IN.equals(parkState)) {
            parking.setParkState(parkState);
            airportParkingMapper.updateParkState(parking);

            if (!Cons.DRIVER_STATE_RUN.equals(driver.getState())) { // 没有接单时，才同步修改司机状态为入栈中。
                addDriverStateRecord(parking.getDriverId(), Cons.DRIVER_STATE_IN, null, null, null, null);
            }
            return;
        }

        if (AbstractParking.STATUS_LEFT.equals(parkState) || AbstractParking.STATUS_CANCELLED.equals(parkState)) {
            if (AbstractParking.STATUS_CANCELLED.equals(parkState)) {
                Integer oldParkState = parking.getParkState();
                if (AbstractParking.STATUS_PREIN.equals(oldParkState)
                        || AbstractParking.STATUS_IN.equals(oldParkState)) {
                    if (!Cons.DRIVER_STATE_RUN.equals(driver.getState())) { // 没有接单时，才同步修改司机状态为入栈中。
                        addDriverStateRecord(parking.getDriverId(), Cons.DRIVER_STATE_STAY, null, null, null, null);
                    }
                }
            }

            // 移入历史表、设置为空闲车位、给下一个司机发送入栈邀请
            archiveDriverParking(parking, parkState);

            return;
        }
    }

    private void updateStationParkState(Driver driver, StationParking parking, Integer parkState) {
        if (AbstractParking.STATUS_PREIN.equals(parkState)) {
            parking.setParkState(parkState);
            parking.setParkBeginTime(HelpUtil.getNowTime());
            stationParkingMapper.updateParkState(parking);

            if (!Cons.DRIVER_STATE_RUN.equals(driver.getState())) { // 没有接单时，才同步修改司机状态为入栈中。
                addDriverStateRecord(parking.getDriverId(), Cons.DRIVER_STATE_PREIN, null, null, null, null);
            }
            return;
        }

        if (AbstractParking.STATUS_IN.equals(parkState)) {
            parking.setParkState(parkState);
            stationParkingMapper.updateParkState(parking);

            if (!Cons.DRIVER_STATE_RUN.equals(driver.getState())) { // 没有接单时，才同步修改司机状态为入栈中。
                addDriverStateRecord(parking.getDriverId(), Cons.DRIVER_STATE_IN, null, null, null, null);
            }
            return;
        }

        if (AbstractParking.STATUS_LEFT.equals(parkState) || AbstractParking.STATUS_CANCELLED.equals(parkState)) {
            if (AbstractParking.STATUS_CANCELLED.equals(parkState)) {
                Integer oldParkState = parking.getParkState();
                if (AbstractParking.STATUS_PREIN.equals(oldParkState)
                        || AbstractParking.STATUS_IN.equals(oldParkState)) {
                    if (!Cons.DRIVER_STATE_RUN.equals(driver.getState())) { // 没有接单时，才同步修改司机状态为入栈中。
                        addDriverStateRecord(parking.getDriverId(), Cons.DRIVER_STATE_STAY, null, null, null, null);
                    }
                }
            }

            // 移入历史表、设置为空闲车位、给下一个司机发送入栈邀请
            archiveDriverParking(parking, parkState);

            return;
        }
    }

    private void archiveDriverParking(AbstractParking parking, Integer parkState) {
        // 移入历史表
        DriverParking driverParking = new DriverParking();
        driverParking.setDriver_id(parking.getDriverId());
        driverParking.setInvite_time(parking.getInviteTime());
        driverParking.setPark_begin_time(parking.getParkBeginTime());
        driverParking.setPark_end_time(HelpUtil.getNowTime());
        driverParking.setPark_state(parkState);

        // 解锁车位（设置为空闲车位）
        parking.setDriverId(null);
        parking.setInviteTime(null);
        parking.setParkBeginTime(null);
        parking.setParkState(null);
        if (parking instanceof AirportParking) {
            AirportParking airportParking = (AirportParking) parking;

            driverParking.setAirport_id(airportParking.getAirportId());
            driverParking.setStation_id(null);
            driverParking.setParking_id(parking.getKid());
            driverParkingMapper.insert(driverParking);

            airportParkingMapper.updateParkState((AirportParking) parking);

            // 给下一个司机发送入栈邀请
            sendAirportInInvitationToDriver(airportParking.getAirportId());
        } else if (parking instanceof StationParking) {
            StationParking stationParking = (StationParking) parking;

            driverParking.setAirport_id(null);
            driverParking.setStation_id(stationParking.getStationId());
            driverParking.setParking_id(parking.getKid());
            driverParkingMapper.insert(driverParking);

            stationParkingMapper.updateParkState((StationParking) parking);

            // 给下一个司机发送入栈邀请
            sendStationInInvitationToDriver(stationParking.getStationId());
        }
    }

    public Integer selectDriverCount() {
        return driverMapper.selectCountActive(null);
    }

    @Transactional(rollbackFor = Exception.class)
    public void bindDriver(Long autoId, Long driverId) {
        Auto auto = autoService.getAuto(autoId);
        if (null != auto) {
            Driver driver = new Driver();
            driver.setKid(driverId);
            driver.setAutoId(autoId);
            driver.setAutoNo(auto.getAutoNo());
            driverMapper.updateByPrimaryKeySelective(driver);
            driverProducer.addDriver(this.getDriver(driverId, null));
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void unBindDriver(Long autoId, Long driverId) {
        Auto auto = autoService.getAuto(autoId);
        if (null != auto) {
            Driver driver = getDriver(driverId, null);
            driver.setKid(driverId);
            driver.setAutoId(null);
            driver.setAutoNo(null);
            driverMapper.updateByPrimaryKey(driver);
        }
    }

    /**
     * 订单取消时，把司机状态还原成接单前的状态
     *
     * @param driverId
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public void orderCancelled(Long driverId) {
        AbstractParking parking = airportParkingMapper.getParkingByDriverId(driverId);
        if (parking == null) {
            parking = stationParkingMapper.getParkingByDriverId(driverId);
        }

        // 有绑定的车位时，可能还原为待命、入栈中、入栈状态
        if (parking != null) {
            if (AbstractParking.STATE_UNCONFIRM.equals(parking.getParkState())) {
                LOG.info(String.format("司机[%d]有待确认的入栈邀请，状态还原为待命。", driverId));
                addDriverStateRecord(driverId, Cons.DRIVER_STATE_STAY, null, null, null, null,
                        getLastUpdateStateTime(driverId, Cons.DRIVER_STATE_STAY));
                notifyDriverState(driverId, Cons.DRIVER_STATE_STAY);
                notifyDriverParking(driverId, parking); // 通知司机端APP弹出入栈邀请对话框，重新操作一遍入栈确认流程
                return;
            }

            if (AbstractParking.STATUS_PREIN.equals(parking.getParkState())) {
                LOG.info(String.format("司机[%d]有入栈中的入栈邀请，状态还原为入栈中。", driverId));
                addDriverStateRecord(driverId, Cons.DRIVER_STATE_PREIN, null, null, null, null,
                        getLastUpdateStateTime(driverId, Cons.DRIVER_STATE_PREIN));
                notifyDriverState(driverId, Cons.DRIVER_STATE_PREIN);
                notifyDriverParking(driverId, parking); // 通知司机端APP弹出入栈邀请对话框，重新操作一遍入栈确认流程
                return;
            }

            if (AbstractParking.STATUS_IN.equals(parking.getParkState())) {
                LOG.info(String.format("司机[%d]有已入栈的入栈邀请，状态还原为入栈。", driverId));
                addDriverStateRecord(driverId, Cons.DRIVER_STATE_IN, null, null, null, null,
                        getLastUpdateStateTime(driverId, Cons.DRIVER_STATE_IN));
                notifyDriverState(driverId, Cons.DRIVER_STATE_IN);
                return;
            }

            // 理论上不会走到这个分支，因为接到乘客后，订单不可以再取消
        }

        // 没有绑定车位时，根据是否有待命的机场ID或者高铁站ID来确定是否改为待命状态
        Driver driver = driverMapper.selectByPrimaryKey(driverId);
        if ((driver.getAirportId() != null && driver.getAirportId() > 0) // 待命机场
                || (driver.getStationId() != null && driver.getStationId() > 0) // 待命高铁站
                ) {
            LOG.info(String.format("司机[%d]有待命的机场ID或高铁站ID，状态还原为待命。", driverId));
            addDriverStateRecord(driverId, Cons.DRIVER_STATE_STAY, null, null, driver.getAirportId(),
                    driver.getStationId(), getLastUpdateStateTime(driverId, Cons.DRIVER_STATE_STAY));
            notifyDriverState(driverId, Cons.DRIVER_STATE_STAY);
            return;
        }

        // 其他情况改为上线状态
        LOG.info(String.format("司机[%d]未查找到任何还原状态的依据，状态设置为上线。", driverId));
        addDriverStateRecord(driverId, Cons.DRIVER_STATE_ON, null, null, null, null);
        notifyDriverState(driverId, Cons.DRIVER_STATE_ON);
    }

    private Timestamp getLastUpdateStateTime(Long driverId, Integer state) {
        DriverStateRecord record = new DriverStateRecord();
        record.setDriverId(driverId);
        record.setState(state);
        return driverStateRecordMapper.getLastUpdateStateTime(record);
    }

    public void notifyDriverState(Long driverId, Integer state) {
        try {
            if (INVITE_PARK_TYPE_MQTT.equals(notifyStateType)) {
                notifyDriverStateByMqtt(driverId, state);
            } else {
                notifyDriverStateByMqttJpush(driverId, state);
            }
            LOG.info(String.format("给司机[%d]推送状态变更成功，推送方式为%s。", driverId, notifyStateType));
        } catch (Exception e) {
            LOG.error(String.format("给司机[%d]推送状态变更失败，推送方式为%s。", driverId, notifyStateType), e);
        }
    }

    private void notifyDriverStateByMqtt(Long driverId, Integer state) throws MqttException {
        if (mqttProducer == null) {
            LOG.warn(String.format("司机[%d]，MQTT功能未开启，转为jpush推送。请确认kgcx.mqtt.enable配置属性的值是否为true。", driverId));
            notifyDriverStateByMqttJpush(driverId, state);
            return;
        }

        MqttMessage message = new MqttMessage();
        message.setQos(1);
        message.setRetained(false); // 是否是实时发送的消息
        message.setPayload(state.toString().getBytes());

        MqttTopic topic = mqttProducer.getTopic(TopicConst.DRIVER_UPDATE_STATE + "." + driverId);
        topic.publish(message);
    }

    private void notifyDriverStateByMqttJpush(Long driverId, Integer state) {
        // 发送消息
        AuroraPush.pushTargetMsgForDriver(TopicConst.DRIVER_UPDATE_STATE, state.toString(), String.valueOf(driverId),
                AuroraPush.PLATFORM_ANDROID);
    }
}
